package handlers

import (
	"encoding/json"
	"fmt"
	"net/http"
	"sync"
	"time"

	"sysu-giep/internal/database/models"
	"sysu-giep/internal/service"
	"sysu-giep/pkg/auth"
	"sysu-giep/pkg/logger"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"go.uber.org/zap"
)

// WebSocketPrivateChatHandler WebSocket私聊处理器
type WebSocketPrivateChatHandler struct {
	chatService *service.PrivateChatService
	jwtManager  *auth.JWTManager
	upgrader    websocket.Upgrader
	clients     map[uint]*Client
	mutex       sync.RWMutex
}

// Client WebSocket客户端
type Client struct {
	ID       uint
	UserID   uint
	Username string
	Role     string
	Conn     *websocket.Conn
	Send     chan []byte
	Handler  *WebSocketPrivateChatHandler
}

// Message WebSocket消息结构
type Message struct {
	Type      string                 `json:"type"`
	Data      map[string]interface{} `json:"data"`
	Timestamp time.Time              `json:"timestamp"`
	UserID    uint                   `json:"user_id,omitempty"`
	Username  string                 `json:"username,omitempty"`
}

// PrivateMessageData 私聊消息数据
type PrivateMessageData struct {
	ReceiverID uint   `json:"receiver_id"`
	Content    string `json:"content"`
	Type       string `json:"type"`
	ReplyToID  *uint  `json:"reply_to_id,omitempty"`
}

// TypingData 打字状态数据
type TypingData struct {
	ReceiverID uint   `json:"receiver_id"`
	IsTyping   bool   `json:"is_typing"`
	Username   string `json:"username"`
}

// NewWebSocketPrivateChatHandler 创建WebSocket私聊处理器
func NewWebSocketPrivateChatHandler(chatService *service.PrivateChatService, jwtManager *auth.JWTManager) *WebSocketPrivateChatHandler {
	return &WebSocketPrivateChatHandler{
		chatService: chatService,
		jwtManager:  jwtManager,
		upgrader: websocket.Upgrader{
			CheckOrigin: func(r *http.Request) bool {
				// 在生产环境中应该检查来源
				origin := r.Header.Get("Origin")
				// 允许本地开发环境
				if origin == "" || origin == "http://localhost:3000" || origin == "http://127.0.0.1:3000" {
					return true
				}
				// 在生产环境中，应该检查允许的域名列表
				// 这里可以根据实际部署环境进行配置
				return false
			},
			ReadBufferSize:  1024,
			WriteBufferSize: 1024,
		},
		clients: make(map[uint]*Client),
	}
}

// HandleWebSocket 处理WebSocket连接
func (h *WebSocketPrivateChatHandler) HandleWebSocket(c *gin.Context) {
	// 从查询参数获取JWT token
	token := c.Query("token")
	if token == "" {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "缺少认证token"})
		return
	}

	// 验证JWT token
	claims, err := h.jwtManager.ValidateToken(token)
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "无效的认证token"})
		return
	}

	// 升级HTTP连接为WebSocket连接
	conn, err := h.upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		logger.Error(fmt.Errorf("WebSocket升级失败: %w", err))
		return
	}

	// 创建客户端
	client := &Client{
		ID:       claims.UserID,
		UserID:   claims.UserID,
		Username: claims.Username,
		Role:     string(claims.Role),
		Conn:     conn,
		Send:     make(chan []byte, 256),
		Handler:  h,
	}

	// 注册客户端
	h.registerClient(client)

	// 启动客户端处理协程
	go client.writePump()
	go client.readPump()

	// 发送连接成功消息
	welcomeMsg := Message{
		Type:      "connected",
		Data:      map[string]interface{}{"message": "连接成功"},
		Timestamp: time.Now(),
		UserID:    client.UserID,
		Username:  client.Username,
	}
	client.sendMessage(welcomeMsg)

	logger.Info("WebSocket私聊客户端连接",
		zap.Uint("user_id", client.UserID),
		zap.String("username", client.Username),
	)
}

// registerClient 注册客户端
func (h *WebSocketPrivateChatHandler) registerClient(client *Client) {
	h.mutex.Lock()
	defer h.mutex.Unlock()

	// 如果已存在相同用户的连接，先关闭旧连接
	if existingClient, exists := h.clients[client.ID]; exists {
		logger.Info("关闭已存在的WebSocket连接", zap.Uint("user_id", client.ID))
		existingClient.Conn.Close()
		close(existingClient.Send)
	}

	h.clients[client.ID] = client
}

// unregisterClient 注销客户端
func (h *WebSocketPrivateChatHandler) unregisterClient(client *Client) {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	delete(h.clients, client.ID)
	close(client.Send)
}

// broadcastToUser 向特定用户发送消息
func (h *WebSocketPrivateChatHandler) broadcastToUser(userID uint, message Message) {
	h.mutex.RLock()
	client, exists := h.clients[userID]
	h.mutex.RUnlock()

	if exists {
		client.sendMessage(message)
	}
}

// readPump 读取消息
func (c *Client) readPump() {
	defer func() {
		c.Handler.unregisterClient(c)
		c.Conn.Close()
	}()

	// 设置读取超时
	c.Conn.SetReadDeadline(time.Now().Add(60 * time.Second))
	c.Conn.SetPongHandler(func(string) error {
		c.Conn.SetReadDeadline(time.Now().Add(60 * time.Second))
		return nil
	})

	for {
		var msg Message
		err := c.Conn.ReadJSON(&msg)
		if err != nil {
			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
				logger.Error(fmt.Errorf("WebSocket读取错误: %w", err))
			}
			break
		}

		c.handleMessage(msg)
	}
}

// writePump 写入消息
func (c *Client) writePump() {
	ticker := time.NewTicker(54 * time.Second)
	defer func() {
		ticker.Stop()
		c.Conn.Close()
	}()

	for {
		select {
		case message, ok := <-c.Send:
			c.Conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
			if !ok {
				c.Conn.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}

			if err := c.Conn.WriteMessage(websocket.TextMessage, message); err != nil {
				logger.Error(fmt.Errorf("WebSocket写入错误: %w", err))
				return
			}

		case <-ticker.C:
			c.Conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
			if err := c.Conn.WriteMessage(websocket.PingMessage, nil); err != nil {
				return
			}
		}
	}
}

// handleMessage 处理接收到的消息
func (c *Client) handleMessage(msg Message) {
	switch msg.Type {
	case "private_message":
		c.handlePrivateMessage(msg)
	case "ping":
		c.handlePing(msg)
	default:
		logger.Warn("未知的WebSocket消息类型", zap.String("type", msg.Type))
	}
}

// handlePrivateMessage 处理私聊消息
func (c *Client) handlePrivateMessage(msg Message) {
	data, ok := msg.Data["data"].(map[string]interface{})
	if !ok {
		c.sendError("无效的私聊消息数据")
		return
	}

	// 解析消息数据
	receiverIDFloat, ok := data["receiver_id"].(float64)
	if !ok {
		c.sendError("缺少接收者ID")
		return
	}

	content, ok := data["content"].(string)
	if !ok || content == "" {
		c.sendError("消息内容不能为空")
		return
	}

	messageType, ok := data["type"].(string)
	if !ok {
		messageType = "text"
	}

	receiverID := uint(receiverIDFloat)

	// 发送消息到数据库
	chatMessage, err := c.Handler.chatService.SendMessage(
		c.UserID,
		receiverID,
		content,
		models.MessageType(messageType),
		nil, // replyToID
		"",  // fileURL
		"",  // fileName
		nil, // fileSize
	)
	if err != nil {
		c.sendError(fmt.Sprintf("发送消息失败: %v", err))
		return
	}

	// 发送消息给接收者
	receiverMsg := Message{
		Type: "new_private_message",
		Data: map[string]interface{}{
			"message_id": chatMessage.ID,
			"sender_id":  c.UserID,
			"username":   c.Username,
			"content":    content,
			"type":       messageType,
			"sent_at":    chatMessage.SentAt,
		},
		Timestamp: time.Now(),
		UserID:    c.UserID,
		Username:  c.Username,
	}
	c.Handler.broadcastToUser(receiverID, receiverMsg)

	// 发送确认消息给发送者
	confirmMsg := Message{
		Type: "message_sent",
		Data: map[string]interface{}{
			"message_id":  chatMessage.ID,
			"receiver_id": receiverID,
			"sent_at":     chatMessage.SentAt,
		},
		Timestamp: time.Now(),
	}
	c.sendMessage(confirmMsg)
}

// handlePing 处理ping消息
func (c *Client) handlePing(msg Message) {
	pongMsg := Message{
		Type:      "pong",
		Data:      map[string]interface{}{"timestamp": time.Now()},
		Timestamp: time.Now(),
	}
	c.sendMessage(pongMsg)
}

// sendMessage 发送消息
func (c *Client) sendMessage(msg Message) {
	select {
	case c.Send <- c.marshalMessage(msg):
	default:
		close(c.Send)
	}
}

// sendError 发送错误消息
func (c *Client) sendError(errorMsg string) {
	errorResponse := Message{
		Type: "error",
		Data: map[string]interface{}{
			"message": errorMsg,
		},
		Timestamp: time.Now(),
	}
	c.sendMessage(errorResponse)
}

// marshalMessage 序列化消息
func (c *Client) marshalMessage(msg Message) []byte {
	data, err := json.Marshal(msg)
	if err != nil {
		logger.Error(fmt.Errorf("序列化WebSocket消息失败: %w", err))
		return []byte{}
	}
	return data
}
